package com.kevin.util;

import org.apache.tools.zip.ZipEntry;
import org.apache.tools.zip.ZipFile;
import org.apache.tools.zip.ZipOutputStream;

import java.io.*;
import java.util.Enumeration;

public class ZipUtil {

    private static final int BUFFERED_SIZE = 1024 * 5;

    /**
     * 压缩文件
     *
     * @param zipFileName   保存的压缩包文件路径
     * @param inputFilePath 需要压缩的文件夹或者文件路径
     * @param isDelete      是否删除源文件
     */
    public static void zip(String zipFileName, String inputFilePath, boolean isDelete) throws IOException {
        zip(new File(zipFileName), new File(inputFilePath), isDelete);
    }

    /**
     * 压缩文件
     *
     * @param zipFile   保存的压缩包文件路径
     * @param inputFile 需要压缩的文件夹或者文件
     * @param isDelete  是否删除源文件
     */
    public static void zip(File zipFile, File inputFile, boolean isDelete) throws IOException {
        if (!inputFile.exists()) {
            throw new FileNotFoundException("在指定路径未找到需要压缩的文件!" + inputFile.getAbsolutePath());
        }

        try (ZipOutputStream out = new ZipOutputStream(new FileOutputStream(zipFile))) {
            zip(out, inputFile, "", isDelete);
        }
    }

    /**
     * 递归压缩方法
     *
     * @param out       压缩包输出流
     * @param inputFile 需要压缩的文件
     * @param base     压缩的路径
     * @param isDelete 是否删除源文件
     */
    private static void zip(ZipOutputStream out, File inputFile, String base, boolean isDelete) throws IOException {
        FileInputStream in = null;
        try {
            if (inputFile.isDirectory()) { // 如果是目录
                File[] inputFiles = inputFile.listFiles();
                out.putNextEntry(new ZipEntry(base + "/"));
                base = base.length() == 0 ? "" : base + "/";
                if (inputFiles != null) {
                    for (File file : inputFiles) {
                        zip(out, file, base + file.getName(), isDelete);
                    }
                }
            } else { // 如果是文件
                if (base.length() > 0) {
                    out.putNextEntry(new ZipEntry(base));
                } else {
                    out.putNextEntry(new ZipEntry(inputFile.getName()));
                }

                in = new FileInputStream(inputFile);
                int len;
                byte[] buff = new byte[BUFFERED_SIZE];
                while ((len = in.read(buff)) != -1) {
                    out.write(buff, 0, len);
                }
                out.flush();
            }
        } finally {
            if (in != null) {
                in.close();
            }
        }

        if (isDelete) {
            inputFile.delete();
        }
    }

    /**
     * 解压缩
     *
     * @param zipFilePath  压缩包路径
     * @param fileSavePath 解压路径
     * @param isDelete     是否删除源文件
     */
    public static void unZip(String zipFilePath, String fileSavePath, boolean isDelete) throws IOException {
        File zFile = new File(zipFilePath);
        if ((!zFile.exists())) {
            throw new FileNotFoundException("要解压的文件不存在!" + zipFilePath);
        }

        File sDir = new File(fileSavePath);
        sDir.mkdirs();

        try (ZipFile zipFile = new ZipFile(zFile)) {
            String savePath = sDir.getAbsolutePath();
            String zipEntryName;
            String tempEntryPath;

            Enumeration<ZipEntry> enume = zipFile.getEntries();
            while (enume.hasMoreElements()) {
                ZipEntry zipEntry = enume.nextElement();
                zipEntryName = zipEntry.getName();
                tempEntryPath = savePath + File.separator + zipEntryName;

                if (zipEntry.isDirectory()) {
                    new File(tempEntryPath).mkdirs();
                } else {
                    BufferedInputStream bis = new BufferedInputStream(zipFile.getInputStream(zipEntry));
                    for (int i = 0; i < zipEntryName.length(); i++) {   // 建目录
                        if (zipEntryName.substring(i, i + 1).equalsIgnoreCase("/")) {
                            String subTemp = savePath + File.separator + zipEntryName.substring(0, i);
                            File subdir = new File(subTemp);
                            if (!subdir.exists())
                                subdir.mkdir();
                        }
                    }
                    BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(tempEntryPath));
                    int len;
                    byte[] buff = new byte[BUFFERED_SIZE];
                    while ((len = bis.read(buff)) != -1) {
                        bos.write(buff, 0, len);
                    }
                    bos.flush();
                }
            }

            if (isDelete) {
                zFile.delete();
            }
        }
    }

    public static void main(String[] args) throws Exception {
        ZipUtil.zip("D:/tmp/test.zip", "D:\\tmp\\test", true);
//        ZipUtil.unZip("D:/tmp/test.zip", "D:/tmp/test", false);
    }
}

